//
//  RecordViewController.m
//  iHealthEHR
//
//  Created by Joseph Ayo Akinyele on 3/13/10.
//  Copyright 2010 __MyCompanyName__. All rights reserved.
//

#import "RecordViewController.h"
#import "ProfileCell.h"
#import "CCRObject.h"
#import "XMLParser.h"

@implementation RecordViewController
@synthesize ccrSections, ccrCategoryKey, ccrImageKey;
@synthesize ccrEntries, ccrNotices, ccrDictEntries;
@synthesize myXMLParser, googlehealth;

- (id)initWithStyle:(UITableViewStyle)style {
    // Override initWithStyle: if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
    if (self = [super initWithStyle:style]) {

    }
    return self;
}


- (void)viewDidLoad {
	[self.navigationController setToolbarHidden:NO];	
	//create two buttons, add them to an array and load them in the toolbar
	UIBarButtonItem *newButton = [[UIBarButtonItem alloc] initWithTitle:@"GH Info" style:UIBarButtonItemStyleBordered target:self action:@selector(loadinfo)];

	UIBarButtonItem *cacheButton = [[UIBarButtonItem alloc] initWithTitle:@"Cache Records Now" style:UIBarButtonItemStyleBordered target:self action:@selector(cacheRecordsNow)];

	NSArray *buttons = [[NSArray alloc] initWithObjects:newButton, cacheButton, nil];
	// each view controller has its own toolbar that can be set appropriately.
	[self setToolbarItems:buttons];
	[newButton release];
	[buttons release];	
	
	// TODO: to support other multi-view (Google Health + Hospital), refactor this section! Basically ccrSections, ccrCategoryKey will
	// passed to this object on creation of the view controller.
	if(ccrSections == nil) {	
		ccrSections = [[NSArray alloc] initWithObjects:@"Notices", @"Demographics", @"Conditions", @"Medications",
					  @"Allergies", @"Procedures", @"Test Results", @"Immunizations", @"Insurance", nil];
	}
	
	if(ccrCategoryKey == nil) {		
		ccrCategoryKey = [[NSArray alloc] initWithObjects:@"NOTICES", @"DEMOGRAPHICS", @"CONDITION", @"MEDICATION",
					   @"ALLERGY", @"PROCEDURE", @"LABTEST", @"IMMUNIZATION", @"PAYER", nil];
	}
	
	if(ccrImageKey == nil) {
		ccrImageKey = [[NSArray alloc] initWithObjects:@"Info-64.png", @"People-64.png", @"StethoBleu-64.png", @"Pills-64.png", 
					   @"Genetics-64.png", @"Case-64.png", @"Caducee-64.png", @"Seringue-64.png", @"HealthShield-64.png", nil];
		ccrCacheImage = [[NSMutableArray alloc] init];
		for(int i = 0; i < [ccrImageKey count]; i++) {
			UIImage *image = [UIImage imageNamed:[ccrImageKey objectAtIndex:i]];
			[ccrCacheImage insertObject:image atIndex:i];
		}
	}
	
	if(myXMLParser == nil) {
		myXMLParser = [[XMLParser alloc] init];
	}
	
	if(cpabe == nil) {
		cpabe = [[CPABEInterface alloc] init];
		[cpabe Initialize];
		[cpabe ReadParameters];
		
		/* temporary */
		[cpabe RetrieveKey:nil with:nil];
		if(detailedView == nil) {
			detailedView = [[DetailedViewController alloc] initWithNibName:nil bundle:nil];
			detailedView.ptrToCPabe = cpabe;
		}		
	}
	
	// construct all the CCR objects (only once)
	if(ccrDictEntries == nil) {
		ccrDictEntries = [[NSMutableDictionary alloc] init];
		for (int i = 1; i < [ccrCategoryKey count]; i++) {
			NSString *selSection = [ccrCategoryKey objectAtIndex:i];
			NSLog(@"Constructing CCR object for: %@", selSection);
			NSArray *array = [self constructCCRObjects:selSection];
			if(array != nil) {
				[ccrDictEntries setObject:array forKey:selSection];
				[array release];
			}
		}
	}
	
	self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithTitle:@"Logout" style:UIBarButtonItemStylePlain 
																			  target:self action:@selector(logout)] autorelease];
	lastProfile = self.title;
	[super viewDidLoad];

    // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
    // self.navigationItem.rightBarButtonItem = self.editButtonItem;
}

-(void) loadinfo
{
	// if mvc is active ViewController, then do nothing!
	NSString *title = @"About Us";
	
	if(info == nil) {
		info = [[MedsViewController alloc] initWithNibName:@"MedsViewController" bundle:nil];
	}	
	info.title = title;
	info.curCategory = @"gh";
	[self.navigationController pushViewController:info animated:YES];
}


- (void)viewWillAppear:(BOOL)animated {
	[self.navigationController setToolbarHidden:NO];
	[self.tableView reloadData];
	if(ccrEntries == nil) {
		NSLog(@"No record to display? Not good.");
	}
	
	if([self.title isEqualToString:lastProfile]) {
		NSLog(@"Still viewing same profile.");
	}
	else {
		/* release all data and call viewDidLoad? */
		if(ccrDictEntries != nil)	
			[ccrDictEntries release];
		// construct all the CCR objects (only once)
		ccrDictEntries = [[NSMutableDictionary alloc] init];
		for (int i = 1; i < [ccrCategoryKey count]-1; i++) {
			NSString *selSection = [ccrCategoryKey objectAtIndex:i];
			NSLog(@"Constructing CCR object for: %@", selSection);
			NSArray *array = [self constructCCRObjects:selSection];
			if(array != nil) {
				[ccrDictEntries setObject:array forKey:selSection];
				[array release];
			}
		}		
	}
	// test function call 
	// [self getEntryByCategory:[ccrCategoryKey objectAtIndex:3]];
    [super viewWillAppear:animated];
}

/*
- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
}
*/
/*
- (void)viewWillDisappear:(BOOL)animated {
	[super viewWillDisappear:animated];
}

- (void)viewDidDisappear:(BOOL)animated {
	[super viewDidDisappear:animated];
}
*/

/*
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    // Return YES for supported orientations
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
*/

- (void)didReceiveMemoryWarning {
	// Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];
	
	// Release any cached data, images, etc that aren't in use.
}

- (void)viewDidUnload {
	// Release any retained subviews of the main view.
	// e.g. self.myOutlet = nil;
}


#pragma mark Table view methods

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}


// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return [ccrSections count];
}


// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    static NSString *ProfileCellIdentifier = @"ProfileCellIdentifier";
    
    ProfileCell *cell = (ProfileCell *)[tableView dequeueReusableCellWithIdentifier:ProfileCellIdentifier];
    if (cell == nil) {
        //cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
		// load nib life
		NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"ProfileCell" 
													 owner:self 
												   options:nil];
		// retrieve cell object in nib file.
		cell = [nib objectAtIndex:0];
    }
    
    // Set up the cell...
	NSUInteger row = [indexPath row];
	cell.section.text = [ccrSections objectAtIndex:row];
	// get number of entires in this specific CCR category
	if(row == 0) {
		// counting register feeds
		cell.item.text = [self getNoticesCount];
	}
	else {
		cell.item.text = [self getItemCount:[ccrCategoryKey objectAtIndex:row]];
	}
	cell.imageView.image = [ccrCacheImage objectAtIndex:row];
    return cell;
}

// Pull the corresponding section of the medical record.
// i.e. if 'Procedures' selected, then pull the procedure entries.
// TODO: May have to refactor code to support multi-view (Google Health + JHU Hospital)
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {    
	NSString *selSection = [ccrCategoryKey objectAtIndex:[indexPath row]];

	if([selSection isEqualToString:@"NOTICES"]) {
		// load the appropariate view
		NSArray *na = [self getNoticeArray];
		if([na count] == 0) {
			[na release];
		}
		else {
			if(noticeView == nil) {
				noticeView = [[NoticeViewController alloc] initWithNibName:nil bundle:nil];
			}
			noticeView.noticeEntry = na;
			noticeView.title = [ccrSections objectAtIndex:[indexPath row]];
			[self.navigationController pushViewController:noticeView animated:YES];
			[na release];
		}
		return;
	}

	// get references to entries for currently selected section (no need to free these objects)
	NSArray *entries = [self.ccrDictEntries objectForKey:selSection];

	// perform XML parsing on demographic entries
	if([selSection isEqualToString:@"DEMOGRAPHICS"]) {
		//NSLog(@"Listing entries...");	
		for(int i = 0; i < [entries count]; i++) {
			CCRObject *c = [entries objectAtIndex:i];
			// NSLog(@"entry name = %@", c.item);
			[myXMLParser parseDemographics:c.item fromElement:c.XmlElement];			
		}		
#ifdef HEALTH_DEBUG		
		NSEnumerator *kN = [myXMLParser.tag keyEnumerator];
		NSString *key;
		while( (key = [kN nextObject]) != nil) {
			NSLog(@" Key: '%@' => Value: '%@'", key, [myXMLParser.tag objectForKey:key]);
		}
#endif
		// load the demographics view to display the demographics information.
		if(demographicsView == nil) {
			demographicsView =  //[[DemViewController alloc] initWithNibName:nil bundle:nil];
				[[DemViewController alloc] initWithStyle:UITableViewStyleGrouped];
		}		
		demographicsView.personalInformation = myXMLParser.tag;
		demographicsView.title = [ccrSections objectAtIndex:[indexPath row]];
		
		[self.navigationController pushViewController:demographicsView animated:YES];
		return;
	}
	else {	
		if(entries != nil) {
			SEL myOptions = @selector(myCCROptionsGH);
			// SEL myOptions = @selector(presentSheet);
			detailedView.ccrObjects = entries;
			detailedView.title = [ccrSections objectAtIndex:[indexPath row]];
			detailedView.ccrSubSection = selSection; // may need to pass on to WebView?
			detailedView.googlehealth = googlehealth;
			detailedView.LoggedInThruGoogleHealth = YES;
			detailedView.selTarget = self;
			detailedView.selFunction = myOptions;
			[self.navigationController pushViewController:detailedView animated:YES];		
		}
	}
}

-(NSIndexPath *) tableView: (UITableView *) tableView
  willSelectRowAtIndexPath: (NSIndexPath *)indexPath
{
	return indexPath;
}


/*
-(void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath {
	NSLog(@"Row selected for '%@' section", [ccrCategoryKey objectAtIndex:[indexPath row]]);
}
*/
 
/*
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
    // Return NO if you do not want the specified item to be editable.
    return YES;
}
*/


/*
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
    
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        // Delete the row from the data source
        [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:YES];
    }   
    else if (editingStyle == UITableViewCellEditingStyleInsert) {
        // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
    }   
}
*/


/*
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath {
}
*/


/*
// Override to support conditional rearranging of the table view.
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
    // Return NO if you do not want the item to be re-orderable.
    return YES;
}
*/

- (void)dealloc {
	[cpabe CleanUp];
	[cpabe release];
	[ccrDictEntries release];
	[ccrSections release];
	[ccrCategoryKey release];
	[ccrImageKey release];
	[ccrCacheImage release];
	[ccrEntries release];
	[ccrNotices release];
	[myXMLParser release];
	[googlehealth release];
	[info release];
    [super dealloc];
}

#pragma mark -
#pragma mark CCR functions
// Count up how many items in the selected CCR section.
-(NSString *)getItemCount:(NSString *)section
{
	// in case entries arent set.	
	GDataEntryHealthProfile *entry;
	
	int maxCount = [ccrEntries count];
	int itemCount = 0;
	for(int i = 0; i < maxCount; i++) {
		// Retrieve each profile 
		entry = [ccrEntries objectAtIndex:i];
		if (entry) {
			NSString *ccrTerm = [[entry CCRCategory] term];
			NSString *itemTerm = [[entry healthItemCategory] term];
			if([ccrTerm isEqualToString:section] && itemTerm != nil) {
				itemCount++;
			}
		}		
	}
	
	return [NSString stringWithFormat:@"%d items", itemCount];
}

-(NSString *) getNoticesCount
{
	if(self.ccrNotices != nil) {
		return [NSString stringWithFormat:@"%d items", [self.ccrNotices count]];  
	}
	else {
		return @"Empty";
	}
}

-(NSArray *) constructCCRObjects:(NSString *)section
{
#ifdef LOG_DEBUG	
	NSLog(@"Retrieve section '%@'?", section);
#endif
	GDataEntryHealthProfile *entry;
	GDataObject *xmlObject;
	NSMutableArray *array = [[NSMutableArray alloc] init];
	
	int maxCount = [ccrEntries count];
	int found = 0;
	for(int i = 0; i < maxCount; i++) {
		entry = [ccrEntries objectAtIndex:i];
		if (entry) {
			
			NSDate *editDate = [[entry editedDate] date];
			NSString *ccrTerm = [[entry CCRCategory] term];
			NSString *itemTerm = [[entry healthItemCategory] term];
			
			if([ccrTerm isEqualToString: section] && itemTerm != nil) {
				found++;
				// also show the xml for the profile entry's CCR or metadata
				xmlObject = [entry continuityOfCareRecord];
				NSXMLElement *element = [xmlObject XMLElement];
				
				CCRObject *ccrObject = [[CCRObject alloc] init];
				ccrObject.editDate = editDate;
				ccrObject.item = itemTerm;
				ccrObject.XmlElement = element;
				ccrObject.ccrsection = section;
				[ccrObject initOtherXMLObjects];
#ifdef LOG_DEBUG	
				NSString *displayStr = [NSString stringWithFormat:@"%@: %@/%@",
										editDate, ccrTerm, itemTerm];
				// [element rootElement]
				NSLog(@"-------------------");
				NSLog(@"String: ['%@']", displayStr);
				// NSLog(@"CCR in XML: %@", element);
				NSLog(@"-------------------");
#endif				
				// dynamically addd item to list for section
				[array addObject:ccrObject];
				[ccrObject release];
			}
		}
		
	}
	
	if(found == 0) {
		[array release];
		return nil;
	}
	
	// caller must free
	return array;	
}

-(NSArray *) getNoticeArray
{
	NSMutableArray *array = [[NSMutableArray alloc] init];
	
	int max = [self.ccrNotices count];	
	for(int i = 0; i < max; i++) {		
		GDataEntryHealthRegister *registryEntry = [self.ccrNotices objectAtIndex:i];
		//NSLog(@"item => %@", [[registryEntry title] stringValue]);
		NSArray *authors = [registryEntry authors];
		// NSString *email = [[authors objectAtIndex:0] email];
		NSString *auth = [[authors objectAtIndex:0] name];
		//NSLog(@"authors => %@ %@", auth, email);
		//NSLog(@"date => %@", [registryEntry publishedDate]);
		
		CCRObject *c = [[CCRObject alloc] init];
		c.item = [[registryEntry title] stringValue];
		c.description = auth;
		c.editDate = [[registryEntry publishedDate] date];
		[array addObject:c];
		[c release];
	}
	
	if(max == 0) {
		[array release];
		return nil;
	}
		
	return array;
}

#pragma mark -
#pragma mark CCR options methods in Google Health Interface. 
-(void) logout
{
	NSLog(@"Are you sure?");
	[self.navigationController popToRootViewControllerAnimated:YES];
}

/* Login to Hospital and download users session-key */
-(void) myCCROptionsGH 
{
	UIActionSheet *menu = [[UIActionSheet alloc]
						   initWithTitle:@"Options" 
						   delegate:self 
						   cancelButtonTitle:@"Cancel" 
						   destructiveButtonTitle:@"Help" 
						   otherButtonTitles:@"Decrypt All", nil];
	[menu showInView:detailedView.view];	
}

-(void) actionSheet:(UIActionSheet *) actionSheet clickedButtonAtIndex:(NSInteger) buttonIndex
{
	// printf("User selected : %i\n", buttonIndex);
	if(buttonIndex == 0) {
		NSLog(@"View Help here?");
		// display a list of
	}
	else if(buttonIndex == 1) {
		NSLog(@"Decrypt section of CCR: %@", detailedView.ccrSubSection);
		NSString *status = [[NSString alloc] initWithFormat:@"Decrypting %@ section...", detailedView.ccrSubSection]; 
		[detailedView showTheProgress:status];
		[status release];
		
		NSArray *entries = detailedView.ccrObjects;
		BOOL _decrypt = NO;
#ifdef LOG_DEBUG		
		printf("There are %i entries\n", [entries count]);
#endif		
		// means we decrypt
		for(int i = 0; i < [entries count]; i++) {
			CCRObject *c = [entries objectAtIndex:i];
			if([c decryptElementFromGoogleHealth:cpabe] == YES) {
				NSString *text = [self parseDescription:c ofCCR:detailedView.ccrSubSection];
				c.item = text;
				// NSLog(@"New text = %@", text);
				_decrypt = YES;
				detailedView.UserSelectedDecryption = YES;
				/* Should be set up front */
				detailedView.ptrToCPabe = cpabe;
			}
		}
		
		if(_decrypt == NO) {
			[CCRObject popUpNotice:@"Decrypt" withMessage:@"Nothing to decrypt."];	
		}		
	}
	else {
		NSLog(@"Cancel");
	}
	[detailedView.tableView reloadData];
	[actionSheet release];
}

/*-(void) incrementBar:(id) timer
{
	amountDone += 1.0f;
	CGFloat prog = (amountDone / 20.0);
	printf("Prog: '%5.2f'", prog);
	[progbar setProgress:prog];
	if(amountDone > 20.0) {
		[basesheet dismissWithClickedButtonIndex:0 animated:YES];
		[timer invalidate];
	}
}

-(void) presentSheet
{
	if(basesheet == nil) {
		basesheet = [[UIActionSheet alloc] initWithTitle:@"Please Wait" 
												delegate:self 
									   cancelButtonTitle:nil 
								  destructiveButtonTitle:nil 
									   otherButtonTitles:nil];
		[basesheet setNumberOfRows:5];
		[basesheet setMessage:@"Updating something here..."];		
		
		progbar = [[UIProgressView alloc] initWithFrame:CGRectMake(50.0f, 70.0f, 220.0f, 90.0f)];
		[progbar setProgressViewStyle:UIProgressViewStyleDefault];
		[basesheet addSubview:progbar];
		[progbar release];
	}
	
	// Create the demonstration updates
	[progbar setProgress:(amountDone = 0.0f)];
	[NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(incrementBar:) userInfo:nil repeats:YES];
	[basesheet showInView:detailedView.view];	
}
 */

// changes the name of the ccr object item and description
// if data contains encrypted XML tags, mark it so.
-(NSString *) parseDescription:(CCRObject *) object ofCCR:(NSString *) section
{
	NSString *text = nil;
	NSEnumerator *eN;
	NSXMLElement *xml = [object getPlainText];
	
	NSArray *n = [xml elementsForName:@"Body"];
	NSXMLNode *e = [n objectAtIndex:0];	
	NSArray *desc;
	if([section isEqualToString:@"MEDICATION"] ||
	   [section isEqualToString:@"IMMUNIZATION"]) {
		desc = [XMLParser findChild:e withTag:@"ProductName"];
	}
	else if([section isEqualToString:@"PAYER"]) {
		desc = [XMLParser findChild:e withTag:@"Type"];
	}
	else {
		desc = [XMLParser findChild:e withTag:@"Description"];
	}
	
	if([section isEqualToString:@"ALLERGY"])
		eN = [[[desc objectAtIndex:1] children] objectEnumerator];		
	else
		eN = [[[desc objectAtIndex:0] children] objectEnumerator];
		
	NSXMLNode *tmp;
	while(tmp = [eN nextObject]) {
		if([[tmp name] isEqualToString:@"Text"]) {
			NSLog(@"Text => %@", [tmp stringValue]);
			text = [tmp stringValue];
		}
	}
	
	// NSLog(@"parse Description => %@", xml);
	[desc release];
	//	[xmlParser release];
	return text;
}

#pragma mark -
#pragma mark CCR caching functions

/* Cache Options: On-demand or behind-the-scene when user logs out? */
-(void) cacheRecordsNow
{
	/* cache all the encrypted records only */
	if(ccrDictEntries == nil) 
		return;
	NSError *error = nil;
	NSLog(@"Cache Records Now for: '%@'", lastProfile);
	SqliteInterface *sql = [[SqliteInterface alloc] initWith:lastProfile];
	
	// If records table doesn't already exist, then create it.
	[sql createRecordTable];
	
	// For each CCR category, find encrypted objects (exclude first two: NOTICES and DEMOGRAPHICS)
	for(int i = 2; i < [ccrCategoryKey count]; i++) {
		NSArray *entries = [self.ccrDictEntries objectForKey:[ccrCategoryKey objectAtIndex:i]];
		
		for (int j = 0; j < [entries count]; j++) {
			CCRObject *c = [entries objectAtIndex:j];
			if([c isEntryEncrypted] == YES) {
				// Retrieve ID first then do what we do.
				NSXMLNode *actor = [c getEncryptedSource];
				// parse the ABE data, decrypt and reconstruct the XML
				NSString *abedata = nil;
				NSEnumerator *e = [[actor children] objectEnumerator];
				NSXMLNode *actorRole;
				while(actorRole = [e nextObject]) {
					if([[actorRole name] isEqualToString:@"ActorRole"]) {
						NSString *blob64 = [actorRole stringValue];
						// NSLog(@"Blob-64 => '%@'", blob64);
						abedata = [CCRObject base64Decode:blob64];
						break;
					}
				}
				NSXMLElement *encryptedData = [[NSXMLElement alloc] initWithXMLString:abedata error:&error];
				NSXMLNode *encrypted = [[encryptedData elementsForName:@"Encrypted"] objectAtIndex:0];
				
				// Recover the 'id' on the encrypted record to later identify the record. 
				NSXMLElement *encryptedElement = (NSXMLElement *) encrypted;
				NSXMLNode *s = [encryptedElement attributeForName:@"id"];
				NSString *idAttr = [s stringValue];
				NSLog(@"ID attribute => '%@'", idAttr);
				[encryptedData release];
				// cache this record : id from XML, section, and the Encrypted XML 
				int err = [sql insertCCR:idAttr inSection:[ccrCategoryKey objectAtIndex:i] withXML:c.encryptedXmlElement];
				if(err != SQLITE_DONE) {
					LOG_CONSOLE("Could not cache record with id = '%s'. Error code: '%i'", [idAttr UTF8String], err);
				}
				// [encrypted release];
			}		
		}				
	}
	[sql release];
}


@end

